﻿using System;
using System.IO;
using System.Net;
using System.Web;
using System.Web.Mvc;
using Newtonsoft.Json.Linq;
using NHibernate;
using Web.Extensions;
using Web.HelperClasses.AvatarService;
using Web.Model;

namespace Web.Controllers
{
    public class FacebookLoginController : OAuthLoginController
    {
		protected override string TokenManagerKey
		{
			get { return "FacebookTokenManager"; }
		}
		protected override string CustomerKey
		{
			get { return "facebookAppID"; }
		}
		protected override string CustomerSecret
		{
			get { return "facebookAppSecret"; }
		}

        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Head)]
        public override ActionResult SendRequest(Uri callbackUri)
        {
            if (!String.IsNullOrEmpty(Request.QueryString["error"]))
                return
                    Content(String.Format("{0} {1} {2}", Request.QueryString["error_reason"], Request.QueryString["error"],
                                          Request.QueryString["error_description"]));

            //если ещё не аутентифицировались
            var tokenManager = GetTokenManager();
            var first = String.Format(
            "https://www.facebook.com/dialog/oauth?client_id={0}&redirect_uri={1}&scope=email",
            tokenManager.ConsumerKey,
            Uri.EscapeDataString(Url.ActionAbsolute("Callback") + "?callbackUri=" + Uri.EscapeDataString(callbackUri.ToString()))
            );
            return Redirect(first);
        }

        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Head)]
        public override ActionResult Callback(Uri callbackUri)
        {
            var code = Request.QueryString["code"];
            //если уже есть код аутентификации, осталось только получить access_token
            if (!String.IsNullOrEmpty(code))
            {
                var tokenManager = GetTokenManager();
                var second =
                    String.Format(
                        "https://graph.facebook.com/oauth/access_token?client_id={0}&redirect_uri={1}&client_secret={2}&code={3}",
                        tokenManager.ConsumerKey,
                        Uri.EscapeDataString(Url.ActionAbsolute("Callback") + "?callbackUri=" + Uri.EscapeDataString(callbackUri.ToString())),
                        tokenManager.ConsumerSecret,
                        code);

                var req = (HttpWebRequest)WebRequest.Create(second);
                var response = req.GetResponse();
                var responseStream = response.GetResponseStream();

                if (responseStream == null)
                    return Content("Error in reading response");
                var responseCollection = HttpUtility.ParseQueryString(new StreamReader(responseStream).ReadToEnd());
                var accessToken = responseCollection.Get("access_token");

                AccountInfo accountInfo;
                try
                {
                    accountInfo = new FacebookAccountInfo(accessToken);
                }
                catch (InvalidDataException ex)
                {
                    return Content(ex.Message);
                }

                CreateOrAuthorizeUser(accountInfo);
            }
            return Redirect(callbackUri != null ? callbackUri.ToString() : Url.Action("Index", "Home"));
        }

        public FacebookLoginController(ISession session, IUserSession userSession, AvatarService avatarService)
            : base(session, userSession, avatarService)
        {
        }
    }

    internal class FacebookAccountInfo : AccountInfo
    {
        public FacebookAccountInfo(string accessToken)
        {
            var third = String.Format("https://graph.facebook.com/me?access_token={0}", accessToken);
            var req = (HttpWebRequest)WebRequest.Create(third);
            var response = req.GetResponse();
            var responseStream = response.GetResponseStream();
            if (responseStream == null)
                throw new InvalidDataException("Error in reading response");
            JObject json = JObject.Parse(new StreamReader(responseStream).ReadToEnd());
            JToken nameJToken, emailJToken, userIdJtoken;
            if (!json.TryGetValue("name", out nameJToken) 
                || 
                !json.TryGetValue("email", out emailJToken)
                ||
                !json.TryGetValue("username", out userIdJtoken)
                )
                throw new InvalidDataException("Bad response");
            Email = emailJToken.Value<string>();
            Name = nameJToken.Value<string>();
            Photo = String.Format(" http://graph.facebook.com/{0}/picture?type=large", userIdJtoken.Value<string>());
            AccountSource = AccountSource.Facebook;
        }

    }
}
